package com.lonni.rpc.core.proxy.jdk;

import com.lonni.rpc.core.commom.RpcMsgType;
import com.lonni.rpc.core.model.RpcRequest;
import com.lonni.rpc.core.model.RpcResponse;
import com.lonni.rpc.core.register.model.Service;
import com.lonni.rpc.core.socket.client.NettyTransport;
import com.lonni.rpc.core.socket.codec.RpcProtocol;
import com.lonni.rpc.core.socket.codec.RpcProtocolHeader;
import com.lonni.rpc.core.spring.SpringContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;

/**
 * 动态代理封装请求
 * @author: Lonni
 * @date: 2024/7/9 0009 15:01
 */
@Slf4j
public class RpcJdkInvocation<T> implements InvocationHandler {
    /**
     * 具体的对象
     */
    private Class<T> tClass;

    /**
     * 服务信息
     */
    private Service service;

    public RpcJdkInvocation(Class<T> tClass, Service service) {
        this.tClass = tClass;
        this.service = service;
    }

    /**
     * 注意 :我们是给远程服务添加调用
     * 此服务可能 不再本jvm中,所以不能直接掉调用method的invoke方法
     *
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Object.class.equals(method.getDeclaringClass())) {
            //排除object类  提供的 toString、hashCode 等方法是不需要代理执行的
            return method.invoke(this, args);
        }
        log.info("接受到rpc请求,执行jdk动态代理invoke");
        //构建rpcrequest
        RpcRequest request = RpcRequest.builder()
                .interfaceName(method.getDeclaringClass().getName())
                .version(service.getVersion())
                .group(service.getGroup())
                .methodName(method.getName())
                .paramTypes(method.getParameterTypes())
                .params(args)
                .requestId(RandomUtils.nextLong())
                .build();
        RpcProtocol<RpcRequest> protocol = new RpcProtocol<>();
        protocol.setBody(request);
        RpcProtocolHeader header = RpcProtocolHeader.builder()
                .msgType((byte) RpcMsgType.REQUEST.ordinal())
                .requestId(request.getRequestId())
                .build();
        protocol.setHeader(header);
        log.info("构建rpc-request信息完成,开始远程调用");
        //开始远程调用
        NettyTransport nettyTransport = SpringContext.getBean(NettyTransport.class);
        CompletableFuture<RpcProtocol<RpcResponse>> resultFuture = (CompletableFuture<RpcProtocol<RpcResponse>>) nettyTransport.transport(protocol);
        RpcProtocol<RpcResponse> resProto = resultFuture.get();
        this.checkRes(resProto.getBody(), request);
        log.info("远程调用成功");
        return resProto.getBody().getData();
    }

    @SneakyThrows
    public void checkRes(RpcResponse response, RpcRequest request) {
        if (response == null) {
            throw new RuntimeException("服务调用失败,interfaceName:" + request.getInterfaceName());
        }
        if (response.getException() != null) {
            throw response.getException();
        }

    }
}



